

package SSF.Net;

import java.util.*;
import java.io.*;

import SSF.Net.Util.*;
import SSF.OS.*;
import com.renesys.raceway.DML.*;
import com.renesys.raceway.SSF.*;

/** Class configuring a level 2 link depending on the number of attached
 *  interfaces: if 2 interfaces are attached it will create an instance
 *  of <TT>SSF.Net.ptpLinkLayer</TT>; if 3 or more interfaces are attached
 *  it will create an instance of <TT>SSF.Net.lanLinkLayer</TT>.
 */
public class link extends Entity implements Configurable {
  Net net;

/** Future link layer interface -- determines level-2 routing semantics for 
  * packets written on any attached interface.  
  */
  linkLayer link_hw;

/** Probe to which traffic is dumped (if non-null) */
  tcpDump dumpTo;

/** Number of attached interfaces */
  int attachedCount;

/** Table mapping NHI addresses, which are "N:N:N:N:H(I)" strings, to 
  * instances of NIC.
  */
  Hashtable attachedInterfaces;

/** CIDR block address, in l1/l2/l3/l4/l5... format */
  String cidr;

/** IP network address of attached interfaces, in a.b.c.d/m format */
  String ip;

/** NHI address of point of link definition */
  String nhi;

/** IP network address of attached interfaces */
  int ipaddr; 

/** IP prefix length (default: /32) */
  int prefix;

/** Transmission delay, in ticks. */
  private double delay;

/** Transmission delay, in ticks. */
  public long delay(){return (long)delay;};

  public link(Net N, String use_nhi) { 
    alignTo(net = N);
    nhi = use_nhi;
    delay = 0.;
    ipaddr = 0;
    prefix = 32;
    attachedInterfaces = new Hashtable();
    attachedCount = 0;
  };

/** Configure the link layer with appropriate delay, addresses,    
  * and a list of attached interfaces.  Creates a link layer 
  * object to handle packet delivery for all attached interfaces; 
  * the specific class of link layer created depends on the number 
  * of attached interfaces, their properties, and any other DML 
  * attributes that might be specified for the link.  In the process of
  * bringing up the link layer, each attached interface is opened() 
  * and properly configured to send and receive packets. 
  */
  public void config(Configuration cfg) throws configException {

    // Get the optional timeline (partition) alignment for this link ..
    Net.configTimeline(this,cfg); 

    String delaySpec = (String)cfg.findSingle("delay");
    if (delaySpec != null) 
      delay = SSF.Net.Net.seconds((new Double(delaySpec)).doubleValue());

    cidr = (String)cfg.findSingle("cidr");
    ip   = (String)cfg.findSingle("ip");

    for (Enumeration attach = cfg.find("attach");
	 attach.hasMoreElements();) {
      String apoint = (String)attach.nextElement();
      int oparen = apoint.indexOf("(");
      int cparen = apoint.indexOf(")");
      String host_nhi = 
	(nhi.equals("")?"":nhi+":")+apoint.substring(0,oparen); 
      Integer iface_num = new Integer(apoint.substring(oparen+1,cparen));
      Host host = (Host)net.hosts.get(host_nhi);

/*
      System.err.print("Searching for "+host_nhi+" among ");
      for (Enumeration hset = net.hosts.keys();hset.hasMoreElements();) {
	System.err.print(hset.nextElement()+" ");
      }
      System.err.println();
*/
      if (host == null) {
	throw new configException("link attach: no such host: "+host_nhi+" for "+apoint);
      }
      else {
	NIC nic = (NIC)host.interfaceNumbers.get(iface_num);
	if (nic == null) {
	  for (Enumeration iset = host.interfaceNumbers.keys();
	       iset.hasMoreElements();) {
	    Object k = iset.nextElement();
	    // System.err.println(host_nhi+"\t\t"+k+" --> "+host.interfaceNumbers.get(k));
	  }
	  throw new configException("link attach: no such interface "+
				    iface_num+" for host "+host_nhi+"("+host+")");
	} else {
	  attachedInterfaces.put(apoint,host.interfaceNumbers.get(iface_num));
	  attachedCount++;
	  if (ip==null) {
	    ip = net.cidrMap.nhi_to_ip(host_nhi + "("+iface_num+")");
            ipaddr = IP_s.StrToInt(ip);
            prefix = IP_s.getMaskBits(ip);
            ip = IP_s.IPtoString(IP_s.mask(ipaddr,prefix)) + "/" + prefix;
          }
	}
      }
    }

    if (ip!=null) {
      ipaddr = IP_s.StrToInt(ip);
      prefix = IP_s.getMaskBits(ip);
    } else {
      throw new configException("No IP address for link "+this);
    }

    String dumpfile = (String)cfg.findSingle("tcpdump");
    if (dumpfile!=null) try {
      if (NIC.BINARY_TCPDUMP)
	dumpTo = new binaryTcpDump(new FileOutputStream(dumpfile),this);
      else
	dumpTo = new tcpDump
	  (new PrintWriter(new FileOutputStream(dumpfile)),this);
	
    } catch (IOException ioex) {
      ioex.printStackTrace(); // oh well
    }

    if (attachedCount == 2) 
      link_hw = new ptpLinkLayer(this);  
    else 
      link_hw = new lanLinkLayer(this);
  }
}

/*=                                                                      =*/
/*=  Copyright (c) 1997--2000  SSF Research Network                      =*/
/*=                                                                      =*/
/*=  SSFNet is open source software, distributed under the GNU General   =*/
/*=  Public License.  See the file COPYING in the 'doc' subdirectory of  =*/
/*=  the SSFNet distribution, or http://www.fsf.org/copyleft/gpl.html    =*/
/*=                                                                      =*/
